#ifndef ALTAPPLICATION_H
#define ALTAPPLICATION_H

#include <QApplication>
#include <QDir>
#include <QMultiHash>

#if defined(qApp)
#undef qApp
#endif

#define qApp (static_cast<Alt::Application*>(QCoreApplication::instance()))

namespace Alt {
     class MapPlugin;
     class MapEditorPlugin;
     class Plugin;

     /*! Manages any GUI applications in the Alt project. One, and only one, instance of this class should be present globally. */
     class Application : public QApplication {
          Q_OBJECT
     public:
          /*! Constructor.
               \param argc The number of arguments passed to the executable.
               \param argv The full command used to execute this program. */
          Application(int& argc, char** argv);

          /*! Exports material names to a file.
               \param fileName The file to export to.
               \return Whether the operation was successful. */
          static bool exportMaterialNames(const QString& fileName);

          /*! Locates all map editor plugins that can handle to specified map type.
               \param type The type of map.
               \return A list of appropriate plugins. */
          static QList<MapEditorPlugin*> findMapEditorPlugins(const QString& type);

          /*! Locates a plugin to handle the specified map type.
               \param type The type of map.
               \return The appropriate plugin. If one was not found, a null pointer is returned. */
          static MapPlugin* findMapPlugin(const QString& type);

          /*! Imports material names from a file and saves them to the Alt settings file.
               If the file could not be opened or read, no changes are made.
               \param fileName The file to import from.
               \return Whether the operation was successful. */
          static bool importMaterialNames(const QString& fileName);

          /*! All availabile map editor plugins, keyed by map types supported. */
          static const QMultiHash<QString, MapEditorPlugin*>& mapEditorPlugins();

          /*! All availabile map plugins, keyed by map type provided. */
          static const QHash<QString, MapPlugin*>& mapPlugins();

          /*! Retrieves the ID given the material's name, or -1 if the material name could not be found. */
          static int materialId(const QString& materialName);

          /*! Retrieves the name of a material given it's ID, or "unknown" if no name could be found. */
          static QString materialName(int materialId);

          /*! All named materials, keyed by name. */
          static const QHash<QString, int>& materialIds();

          /*! All named materials, keyed by ID. */
          static const QHash<int, QString>& materialNames();


          /*! Directory containing Alt plugins. */
          static const QDir& pluginDir();

          /*! All available Alt plugins, cast as QObject pointers. */
          static const QObjectList& pluginObjects();

          /*! Path to where Alt Plugins can be found. */
          static QString pluginPath();

          /*! All available Alt plugins, in an arbitrary order. */
          static const QList<Plugin*>& plugins();

          /*! Refreshes loaded material names. This is a potentially expensive operation. */
          static void refreshMaterialNames();

     signals:
          /*! Emitted when the material names are refreshed. */
          void materialNamesRefreshed();

     private:
          /*! Searches plugin directory and caches any found plugins. */
          static void buildPluginCache();

          /*! Cache of map editor plugins, keyed by map type. */
          static QMultiHash<QString, MapEditorPlugin*> m_mapEditorPluginCache;

          /*! Cache of map plugins, keyed by map type. */
          static QHash<QString, MapPlugin*> m_mapPluginCache;

          /*! Material name -> ID conversion table. */
          static QHash<QString, int> m_materialNameToIdHash;

          /*! Material ID -> name conversion table. */
          static QHash<int, QString> m_materialIdToNameHash;

          /*! Cache of all Alt plugins. */
          static QList<Plugin*> m_pluginCache;

          /*! Directory containing Alt plugins. */
          static QDir m_pluginDir;

          /*! Cache of all Alt plugins, cast to objects. */
          static QObjectList m_pluginObjectCache;
     };
}

#endif
